using System;
using System.Collections;
using System.Windows.Forms;
using EnvDTE;

namespace NUnitGenAddIn.Core
{
    /// <summary>
    /// Add-in  Helper
    /// </summary>
	public class AddInHelper
	{
        /// <summary>
        /// Application Object
        /// </summary>
		protected DTE _applicationObject;

        /// <summary>
        /// Add-in Instance
        /// </summary>
		protected AddIn _addInInstance;

        /// <summary>
        /// Initializes a new instance of the <see cref="AddInHelper"/> class.
        /// </summary>
        /// <param name="applicationObject">The application object.</param>
        /// <param name="addInInstance">The add in instance.</param>
		public AddInHelper(DTE applicationObject, AddIn addInInstance)
		{
			this._applicationObject = applicationObject;
			this._addInInstance = addInInstance;
		}

        /// <summary>
        /// Adds the command to command bar.
        /// </summary>
        /// <param name="commandName">Name of the command.</param>
        /// <param name="buttonText">The button text.</param>
        /// <param name="toolTip">The tool tip.</param>
        /// <param name="commandBarName">Name of the command bar.</param>
		public void AddCommandToCommandBar(string commandName, string buttonText, string toolTip, string commandBarName)
		{
			DeleteCommand(commandName);
			AddCommand(commandName, buttonText, toolTip, commandBarName);
		}

        /// <summary>
        /// Gets the <c>Namespace</c> from code element list.
        /// </summary>
        /// <param name="codeElements">The code elements.</param>
        /// <returns></returns>
		public CodeNamespace GetNameSpaceFromCodeElementList(ArrayList codeElements)
		{
			foreach (CodeElement element in codeElements)
			{
				if (element.Kind == vsCMElement.vsCMElementNamespace)
					return element as CodeNamespace;
			}
			return null;
		}

        /// <summary>
        /// Gets the project item for class from project.
        /// </summary>
        /// <param name="nameSpaceName">Name of the <c>Namespace</c>.</param>
        /// <param name="className">Name of the class.</param>
        /// <param name="targetProject">The target project.</param>
        /// <returns></returns>
		public ProjectItem GetProjectItemForClassFromProject(string nameSpaceName, string className, Project targetProject)
		{
			CodeType type = targetProject.CodeModel.CodeTypeFromFullName(nameSpaceName + "." + className);
			return (type != null) ? type.ProjectItem : null;
		}

        /// <summary>
        /// Gets the class list from code element list.
        /// </summary>
        /// <param name="codeElements">The code elements.</param>
        /// <returns></returns>
		public ArrayList GetClassListFromCodeElementList(ArrayList codeElements)
		{
			ArrayList classList = new ArrayList();
			foreach (CodeElement codeElement in codeElements)
			{
				if (codeElement.Kind == vsCMElement.vsCMElementClass)
					classList.Add(codeElement as CodeClass);
			}
			return classList;
		}

        /// <summary>
        /// Gets the function list from code element list.
        /// </summary>
        /// <param name="targetCodeElements">The target code elements.</param>
        /// <returns></returns>
		public ArrayList GetFunctionListFromCodeElementList(ArrayList targetCodeElements)
		{
			ArrayList functionList = new ArrayList();
			foreach (CodeElement codeElement in targetCodeElements)
			{
				if (codeElement.Kind == vsCMElement.vsCMElementFunction)
					functionList.Add(codeElement as CodeFunction);
			}
			return functionList;
		}

        /// <summary>
        /// Gets the code element list from point.
        /// </summary>
        /// <param name="currentPoint">The current point.</param>
        /// <returns></returns>
		public virtual ArrayList GetCodeElementListFromPoint(TextPoint currentPoint)
		{
			throw new NotImplementedException(
				"Due to different implementation of FileCodeModel.CodeElementFromPoint in EnvDTE and EnvDTE2, you must implement this function.");
		}

        /// <summary>
        /// Gets the code class from code elements.
        /// </summary>
        /// <param name="codeElements">The code elements.</param>
        /// <returns></returns>
		public virtual CodeClass GetCodeClassFromCodeElements(CodeElements codeElements)
		{
			throw new NotImplementedException(
				"Due to different implementation of CodeElement.Children in EnvDTE and EnvDTE2, you must implement this function.");
		}

        /// <summary>
        /// Gets the code model4 current project item.
        /// </summary>
        /// <returns></returns>
		public FileCodeModel GetCodeModel4CurrentProjectItem()
		{
			ProjectItem projectItem = GetCurrentProjectItem();
			FileCodeModel fileCodeModel = projectItem.FileCodeModel;
			return fileCodeModel;
		}

        /// <summary>
        /// Gets the current project.
        /// </summary>
        /// <returns></returns>
		public Project GetCurrentProject()
		{
			return GetCurrentProjectItem().ContainingProject;
		}

        /// <summary>
        /// Gets the current project item.
        /// </summary>
        /// <returns></returns>
		public ProjectItem GetCurrentProjectItem()
		{
			return GetActiveDocument().ProjectItem;
		}

        /// <summary>
        /// Gets the active document.
        /// </summary>
        /// <returns></returns>
		public Document GetActiveDocument()
		{
			return _applicationObject.ActiveDocument;
		}

        /// <summary>
        /// Gets the solution.
        /// </summary>
        /// <returns></returns>
		public Solution GetSolution()
		{
			return _applicationObject.Solution;
		}

        /// <summary>
        /// Gets the current selection.
        /// </summary>
        /// <returns></returns>
		public TextSelection GetCurrentSelection()
		{
			return GetActiveDocument().Selection as TextSelection;
		}

        /// <summary>
        /// Shows the error message box.
        /// </summary>
        /// <param name="errorMessage">The error message.</param>
		public void ShowErrorMessageBox(string errorMessage)
		{
			MessageBox.Show(errorMessage, _addInInstance.ProgID, MessageBoxButtons.OK, MessageBoxIcon.Error);
		}

        /// <summary>
        /// Shows the information message box.
        /// </summary>
        /// <param name="message">The message.</param>
		public void ShowInformationMessageBox(string message)
		{
			MessageBox.Show(message, _addInInstance.ProgID, MessageBoxButtons.OK, MessageBoxIcon.Information);
		}

        /// <summary>
        /// Executes the command.
        /// </summary>
        /// <param name="topMenuName">Name of the top menu.</param>
        /// <param name="subMenuCommand">The sub menu command.</param>
        /// <param name="commandArgs">The command arguments.</param>
		public void ExecuteCommand(string topMenuName, string subMenuCommand, string commandArgs)
		{
			_applicationObject.ExecuteCommand(string.Format("{0}.{1}", topMenuName, subMenuCommand), commandArgs);
		}

        /// <summary>
        /// Gets the source control.
        /// </summary>
        /// <returns></returns>
		public SourceControl GetSourceControl()
		{
			return _applicationObject.SourceControl;
		}

        /// <summary>
        /// Deletes the command.
        /// </summary>
        /// <param name="commandName">Name of the command.</param>
		protected virtual void DeleteCommand(string commandName)
		{
			Command command = null;
			try
			{
				command = _applicationObject.Commands.Item(_addInInstance.ProgID + "." + commandName, -1);
			}
			catch (Exception)
			{}

			if (command != null)
			{
				command.Delete();
			}
		}

        /// <summary>
        /// Adds the command.
        /// </summary>
        /// <param name="commandName">Name of the command.</param>
        /// <param name="buttonText">The button text.</param>
        /// <param name="toolTip">The tool tip.</param>
        /// <param name="commandBarName">Name of the command bar.</param>
		protected virtual void AddCommand(string commandName, string buttonText, string toolTip, string commandBarName)
		{
			throw new NotImplementedException("You must implement this function in inherited class.");
		}
	}
}